import itertools
from multiprocessing import Process, Lock, Queue
from os import path, popen
from subprocess import Popen, call
import zipfile
import get_dict
# import os


def dictionary_crack(dictionary, file):
    # zip = zipfile.ZipFile(file)
    for password in dictionary:
        # try:
        #     zip.extractall(path='.', pwd=password[0:-2])
        #     print(f'密码：{password}')
        #     break
        # except Exception:
        #     pass
        # 解压成功返回值为0，失败为1
        password = password[0:-2].replace('&', '"&"')
        # print(password)
        if password == '':
            continue
        if call(f'bc x -aoa -p:{password} {file}', shell=True) == 0:
            print(f'密码：{password}')
            break
    print('破解失败')


def get_number_and_letter_password(queue, lock, len=8, start=0, n=100):
    '''
    生成数字字母组合密码
    len：密码长度
    start：密码生成器遍历起始位置
    n：生成密码个数
    '''
    # print(f'进程{os.getpid()}开始破解')
    passwords = (''.join(_) for _ in itertools.product(
        '01234567890123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
        repeat=len))
    # 统计密码生成器的迭代位置
    i = 0
    zip = zipfile.ZipFile('test.zip')
    for _ in passwords:
        # 不能用Queue.full()判断队列是否满了，
        # 由于多线程或多进程的环境，该状态是不可靠的。
        try:
            queue.put(queue.get_nowait())
            # 如果队列有东西证明有进程破解密码成功了
            # print(f'进程{os.getpid()}结束破解')
            exit(0)
        except Exception:
            # 如果队列为空就继续破解
            if (i >= start) and (i < n + start):
                with open(f'{start}.pwd', 'a') as f:
                    f.write(f'{_}:{i}\n')
                try:
                    lock.acquire()
                    zip.extractall(path='.', pwd=_.encode('utf-8'))
                    lock.release()
                    print(f'密码破解成功，解压密码：{_}')
                    queue.put(_)
                except Exception as e:
                    # 出错也要解锁
                    lock.release()
                    # print(e)
        i += 1


def main():
    len = 3
    all = pow(72, len)
    n = all // 8
    lock = Lock()
    queue = Queue(1)
    for _ in range(8):
        # print(_ * n)
        # 在进程池中的进程中使用锁会将进程结束，所以只能手动创建进程
        p = Process(target=get_number_and_letter_password,
                    args=(queue, lock, len, _ * n, n))
        p.start()
        # p.join()
    # 如果还有剩余
    if n * 8 < all:
        get_number_and_letter_password(queue, lock, len=2, start=8 * n)


if __name__ == '__main__':
    # main()
    dictionary_crack(get_dict.read(), '../课程实战项目《小书架》小程序源码.rar')
    # dictionary_crack(get_dict.read(), '../test.zip')


# print(divmod(11.22, 1))
